package com.jevons.geo_lib.helper;

import com.jevons.geo_lib.geojson.MapboxJsonHelper;
import com.jevons.geo_lib.utils.StringUtils;
import com.mapbox.geojson.Geometry;
import com.mapbox.geojson.GeometryCollection;
import com.mapbox.geojson.LineString;
import com.mapbox.geojson.MultiLineString;
import com.mapbox.geojson.MultiPoint;
import com.mapbox.geojson.MultiPolygon;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.Polygon;


import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.io.geojson.GeoJsonReader;
import org.locationtech.jts.io.geojson.GeoJsonWriter;
import org.locationtech.jts.operation.overlay.OverlayOp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/**
 * Copyright 2020 JxGIS
 *
 * @file GeometryHelper
 * @auth linaisheng
 * Created on 2020/11/25.
 * Description：
 */
public class GeometryHelper {

    public static boolean geometryTouches(Geometry geometry1, Geometry geometry2) {
        try {
            GeometryFactory geometryFactory = new GeometryFactory();
            GeoJsonReader jsonReader = new GeoJsonReader(geometryFactory);

            boolean isTouche = jsonReader.read(MapboxJsonHelper.geometryToJson(geometry1)).touches(
                    jsonReader.read(MapboxJsonHelper.geometryToJson(geometry2)));
            return isTouche;
        } catch (Exception e) {}
        return false;
    }


    public List<Point> getPolygonIntersects(Geometry geometry1, Geometry geometry2) {

        List<Polygon> polygons1 = new ArrayList<>();
        if (geometry1 instanceof MultiPolygon) {
            MultiPolygon multiPolygon = (MultiPolygon) geometry1;
            for (List<List<Point>> list : multiPolygon.coordinates()) {
                polygons1.add(Polygon.fromLngLats(list));
            }
        } else if (geometry1 instanceof Polygon) {
            polygons1.add((Polygon) geometry1);
        }

        List<Polygon> polygons2 = new ArrayList<>();
        if (geometry2 instanceof MultiPolygon) {
            MultiPolygon multiPolygon = (MultiPolygon) geometry2;
            for (List<List<Point>> list : multiPolygon.coordinates()) {
                polygons2.add(Polygon.fromLngLats(list));
            }
        } else if (geometry2 instanceof Polygon) {
            polygons2.add((Polygon) geometry2);
        }

        if (polygons1.size() > 0 && polygons2.size() > 0) {
            List<Point> points = new ArrayList<>();
            for (Polygon polygon1 : polygons1) {
                for (Polygon polygon2 : polygons2) {
                    List<Point> data = getPolygonIntersects(polygon1, polygon2);
                    if (data != null) {
                        points.addAll(data);
                    }
                }
            }
            return points;
        }
        return null;
    }


    public List<Point> getPolygonIntersects(Polygon polygon1, Polygon polygon2) {

        LineString line1 = LineString.fromLngLats(polygon1.coordinates().get(0));
        LineString line2 = LineString.fromLngLats(polygon2.coordinates().get(0));

        try {
            GeometryFactory geometryFactory = new GeometryFactory();
            GeoJsonWriter jsonWriter = new GeoJsonWriter(17);
            GeoJsonReader jsonReader = new GeoJsonReader(geometryFactory);


            org.locationtech.jts.geom.Geometry geometry1 = jsonReader.read(toJson(line1));
            org.locationtech.jts.geom.Geometry geometry2 = jsonReader.read(toJson(line2));
            org.locationtech.jts.geom.Geometry interGeometry = geometry1.intersection(geometry2);

            List<Point> commonPoint = new ArrayList<>();
            //如果是LineString或者MultiLineString，则有公共边
            if (interGeometry instanceof org.locationtech.jts.geom.LineString) {
                LineString lineString = LineString.fromJson(jsonWriter.write(interGeometry));
                commonPoint.addAll(lineString.coordinates());
            } else if (interGeometry instanceof org.locationtech.jts.geom.MultiLineString) {
                MultiLineString multiLineString = MultiLineString.fromJson(jsonWriter.write(interGeometry));
                for (LineString lineString : multiLineString.lineStrings()) {
                    commonPoint.addAll(lineString.coordinates());
                }
            } else if (interGeometry instanceof org.locationtech.jts.geom.MultiPoint) {
                MultiPoint multiPoint = MultiPoint.fromJson(jsonWriter.write(interGeometry));
                for (Point point : multiPoint.coordinates()) {
                    double pointLatitude = Double.parseDouble(String.format("%.7f", point.latitude()));
                    double pointLongitude = Double.parseDouble(String.format("%.7f", point.longitude()));
                    //判断该点是不是在其中一个多边形的顶点
                    for (Point vertex : line1.coordinates()) {
                        //因为精度问题，保留7位小数进行比较
                        double latitude = Double.parseDouble(String.format("%.7f", vertex.latitude()));
                        double longitude = Double.parseDouble(String.format("%.7f", vertex.longitude()));


                        if (longitude == pointLongitude && latitude == pointLatitude) {
                            commonPoint.add(point);
                        }
                    }
                }
            } else if (interGeometry instanceof org.locationtech.jts.geom.Point) {
                Point point = Point.fromJson(jsonWriter.write(interGeometry));
                double pointLatitude = Double.parseDouble(String.format("%.7f", point.latitude()));
                double pointLongitude = Double.parseDouble(String.format("%.7f", point.longitude()));
                //判断该点是不是在其中一个多边形的顶点
                for (Point vertex : line1.coordinates()) {
                    double latitude = Double.parseDouble(String.format("%.7f", vertex.latitude()));
                    double longitude = Double.parseDouble(String.format("%.7f", vertex.longitude()));
                    if (longitude == pointLongitude && latitude == pointLatitude) {
                        commonPoint.add(point);
                    }
                }
            } else if (interGeometry instanceof org.locationtech.jts.geom.GeometryCollection) {
                GeometryCollection geometryCollection = GeometryCollection.fromJson(jsonWriter.write(interGeometry));
                //判断该点是不是在其中一个多边形的顶点
                for (Geometry geometry : geometryCollection.geometries()) {
                    if (geometry instanceof LineString) {
                        LineString lineString = (LineString) geometry;
                        commonPoint.addAll(lineString.coordinates());
                    } else if (geometry instanceof MultiLineString) {
                        MultiLineString multiLineString = (MultiLineString) geometry;
                        for (LineString lineString : multiLineString.lineStrings()) {
                            commonPoint.addAll(lineString.coordinates());
                        }
                    }
                }
            }
            return commonPoint;
        } catch (Exception e){}
        return new ArrayList<>();
    }


    //合并
    public Geometry unionGeometry(List<Geometry> geometries) {
        if (geometries.size() > 0) {
            List<org.locationtech.jts.geom.Geometry> geometryList = new ArrayList<>();
            for (int i = 0; i < geometries.size(); i++) {
                try {
                    GeometryFactory geometryFactory = new GeometryFactory();
                    GeoJsonReader jsonReader = new GeoJsonReader(geometryFactory);
                    org.locationtech.jts.geom.Geometry geometry = jsonReader.read(
                            toJson(geometries.get(i)));
                    geometryList.add(geometry);
                } catch (Exception e){}
            }

            if (geometryList.size() > 0) {

                org.locationtech.jts.geom.Geometry geometry = geometryList.get(0);
                int i = 1;
                while (i < geometryList.size()) {
                    org.locationtech.jts.geom.Geometry nextGeometry = geometryList.get(i);
                    OverlayOp op = new OverlayOp(geometry, nextGeometry);
                    try {
                        geometry = op.getResultGeometry(OverlayOp.UNION);
                    } catch (Exception e){
                        return null;
                    }
                    i++;
                }

                GeoJsonWriter jsonWriter = new GeoJsonWriter(17);
                if (geometry instanceof org.locationtech.jts.geom.MultiPolygon) {
                    return MultiPolygon.fromJson(jsonWriter.write(geometry));
                } else if (geometry instanceof org.locationtech.jts.geom.Polygon) {
                    return Polygon.fromJson(jsonWriter.write(geometry));
                } else if (geometry instanceof org.locationtech.jts.geom.MultiLineString) {
                    return MultiLineString.fromJson(jsonWriter.write(geometry));
                } else if (geometry instanceof org.locationtech.jts.geom.LineString) {
                    return LineString.fromJson(jsonWriter.write(geometry));
                } else if (geometry instanceof org.locationtech.jts.geom.MultiPoint) {
                    return MultiPoint.fromJson(jsonWriter.write(geometry));
                } else if (geometry instanceof org.locationtech.jts.geom.Point) {
                    return Point.fromJson(jsonWriter.write(geometry));
                }
                return null;
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    //切割
    public SlicePolygonByLineResult slicePolygonByLine(List<Geometry> geometries, LineString sliceLine) {
        SlicePolygonByLineResult finalResult = new SlicePolygonByLineResult();
        for (Geometry geometry : geometries) {
            if (geometry instanceof MultiPolygon) {
                MultiPolygon multiPolygon = (MultiPolygon) geometry;


                //将多多边形分割为多边形列表
                SlicePolygonByLineResult itemResult = new SlicePolygonByLineResult();
                for (List<List<Point>> coordinates : multiPolygon.coordinates()) {
                    Polygon polygon = Polygon.fromLngLats(coordinates);

                    SlicePolygonByLineResult result = slicePolygonByLine(polygon, sliceLine);
                    if (result != null) {
                        itemResult.addResult(result);
                    } else {
                        itemResult.getResultPolygons().add(polygon);
                    }
                }

                if (itemResult.getResultPolygons().size() != multiPolygon.coordinates().size()) {
                    //和原来的多边形数量不一样，则说明切割成功
                    finalResult.addResult(itemResult);
                }
            } else if (geometry instanceof Polygon) {
                Polygon polygon = (Polygon) geometry;
                SlicePolygonByLineResult result = slicePolygonByLine(polygon, sliceLine);
                if (result != null) {
                    finalResult.addResult(result);
                } else {
                    finalResult.getResultPolygons().add(polygon);
                }
            }
        }

        if (finalResult.getResultPolygons().size() > geometries.size()) {
            //比原来的多边形数量多，则说明切割成功
            return finalResult;
        }
        return null;
    }

    public SlicePolygonByLineResult slicePolygonByLine(Polygon polygon, LineString sliceLine) {
        //先判断内部切割
        List<Polygon> checkSliceInside = doSaveQiegeCheckInside(polygon, sliceLine);
        if (checkSliceInside != null) {
            return new SlicePolygonByLineResult(checkSliceInside);
        }
        try {
            GeometryFactory geometryFactory = new GeometryFactory();
            GeoJsonWriter jsonWriter = new GeoJsonWriter(17);
            GeoJsonReader jsonReader = new GeoJsonReader(geometryFactory);
            org.locationtech.jts.geom.Geometry sliceLineGeometry = jsonReader.read(toJson(sliceLine));

            //外边界多边形
            Polygon outLinePolygon = Polygon.fromLngLats(polygon.coordinates().subList(0, 1));
            org.locationtech.jts.geom.Geometry outLinePolygonsGeometry = jsonReader.read(toJson(outLinePolygon));

            //判断切割线与多边形是否有焦点
            boolean isCrosses = outLinePolygonsGeometry.crosses(sliceLineGeometry);
            if (!isCrosses) {
                return null;
            }


            //判断多边形是否具有孔
            List<org.locationtech.jts.geom.Geometry> hollowPolygons = new ArrayList<>();
            if (polygon.coordinates().size() > 1) {
                int i = 1;
                while (i < polygon.coordinates().size()) {
                    List<List<Point>> list = new ArrayList<>();
                    list.add(polygon.coordinates().get(i));
                    Polygon hollowPolygon = Polygon.fromLngLats(list);
                    hollowPolygons.add(jsonReader.read(toJson(hollowPolygon)));
                    i++;
                }
            }


            //外边界
            LineString polygonOutLine = LineString.fromLngLats(polygon.coordinates().get(0));
            org.locationtech.jts.geom.Geometry polygonsOutLineGeometry = jsonReader.read(toJson(polygonOutLine));

            //多边形被分割后的线段
            org.locationtech.jts.geom.Geometry sliceMultiLineGeometry = new OverlayOp(
                    polygonsOutLineGeometry, sliceLineGeometry).getResultGeometry(OverlayOp.DIFFERENCE);
            //被分割的线段
            MultiLineString multiLineString = MultiLineString.fromJson(jsonWriter.write(sliceMultiLineGeometry));
            if (multiLineString.lineStrings().size() < 3) {
                //只处理切割成三段的结果
                return null;
            }

            //截取分割线
            org.locationtech.jts.geom.Geometry effectiveLine = outLinePolygonsGeometry.intersection(sliceLineGeometry);

            //获取切割点
            List<SlicePoint> slicePoints = getSlicePoint(polygonOutLine, sliceLine);

            if (effectiveLine instanceof org.locationtech.jts.geom.MultiLineString) {
                //具有多条分割线，情况复杂不做切割
                MultiLineString spliceLine = MultiLineString.fromJson(jsonWriter.write(effectiveLine));

                //分段切割，逐步切完

                return null;
            }
            else if (effectiveLine instanceof org.locationtech.jts.geom.LineString) {
                LineString spliceLine = LineString.fromJson(jsonWriter.write(effectiveLine));
                //分割线开始点
                Point startPoint = spliceLine.coordinates().get(0);
                Point endPoint = spliceLine.coordinates().get(spliceLine.coordinates().size() -1);

                //todo 判断切割点是否与相邻点距离小于1毫米

                //分割线的点
                List<Point> splicePointList = spliceLine.coordinates();

                List<List<Point>> coordinatesPolygon1 = new ArrayList<>();
                List<List<Point>> coordinatesPolygon2 = new ArrayList<>();

                //被切割后的三条线段
                LineString slicePolygonLineFirst = multiLineString.lineStrings().get(0);
                LineString slicePolygonLineMid = multiLineString.lineStrings().get(1);
                LineString slicePolygonLineEnd = multiLineString.lineStrings().get(2);

                //判断正序或倒序插入
                if (slicePolygonLineMid.coordinates().get(0).latitude() == startPoint.latitude()
                        && slicePolygonLineMid.coordinates().get(0).longitude() == startPoint.longitude()) {

                    List<Point> points1 = new ArrayList<>();
                    //去掉最后一个点
                    points1.addAll(slicePolygonLineFirst.coordinates().subList(0, slicePolygonLineFirst.coordinates().size() -1));
                    //加入切割线
                    points1.addAll(splicePointList);
                    //去掉第一个点
                    points1.addAll(slicePolygonLineEnd.coordinates().subList(1, slicePolygonLineEnd.coordinates().size()));
                    coordinatesPolygon1.add(points1);


                    List<Point> points2 = new ArrayList<>();
                    //去掉首尾点
                    points2.addAll(slicePolygonLineMid.coordinates().subList(1, slicePolygonLineMid.coordinates().size() - 1));
                    Collections.reverse(splicePointList);
                    points2.addAll(splicePointList);
                    //闭合
                    points2.add(points2.get(0));
                    coordinatesPolygon2.add(points2);

                } else {
                    List<Point> points2 = new ArrayList<>();
                    //去掉首尾点
                    points2.addAll(slicePolygonLineMid.coordinates().subList(1, slicePolygonLineMid.coordinates().size() - 1));
                    points2.addAll(splicePointList);
                    //闭合
                    points2.add(points2.get(0));
                    coordinatesPolygon2.add(points2);

                    List<Point> points1 = new ArrayList<>();
                    //去掉最后一个点
                    points1.addAll(slicePolygonLineFirst.coordinates().subList(0, slicePolygonLineFirst.coordinates().size() -1));
                    //加入切割线
                    Collections.reverse(splicePointList);
                    points1.addAll(splicePointList);
                    //去掉第一个点
                    points1.addAll(slicePolygonLineEnd.coordinates().subList(1, slicePolygonLineEnd.coordinates().size()));

                    coordinatesPolygon1.add(points1);

                }

                List<Polygon> polygons = new ArrayList<>();
                polygons.add(Polygon.fromLngLats(coordinatesPolygon1));
                polygons.add(Polygon.fromLngLats(coordinatesPolygon2));

                //处理孔的问题
                if (hollowPolygons.size() > 0) {
                    //给切割多边形去除孔结构
                    for (int i = 0; i < polygons.size(); i++) {
                        for (int j = 0; j < hollowPolygons.size(); j++) {
                            org.locationtech.jts.geom.Geometry itemPolygon =
                                    jsonReader.read(toJson(polygons.get(i)));

                            org.locationtech.jts.geom.Geometry hollowGeometry = hollowPolygons.get(j);

                            org.locationtech.jts.geom.Geometry result = null;
                            try {
                                result = itemPolygon.difference(hollowGeometry);

                            } catch (Exception e) {

                                //判断切割线与空多边形是否有焦点
                                boolean isCrossesHollow = hollowGeometry.crosses(sliceLineGeometry);

                                if (isCrossesHollow) {
                                    //如果处理空失败且和空相交的话，情况复杂无法切割
                                    return null;
                                }

                                //判断在那个图形内
                                if (itemPolygon.contains(hollowGeometry)) {
                                    //空在这个图形内
                                    Polygon outpolygon = Polygon.fromJson(jsonWriter.write(itemPolygon));
                                    Polygon hollowPolygon = Polygon.fromJson(jsonWriter.write(hollowGeometry));
                                    outpolygon.coordinates().addAll(hollowPolygon.coordinates());
                                    polygons.set(i, outpolygon);
                                }

                            }
                            if (result != null) {
                                polygons.set(i, Polygon.fromJson(jsonWriter.write(result)));
                            }

                        }
                    }

                    //获取孔切割的切割点
                    for (int k = 0; k < hollowPolygons.size(); k++) {
                        Polygon hollowPolygon = Polygon.fromJson(jsonWriter.write(hollowPolygons.get(0)));
                        LineString hollowPolygonOutLine = LineString.fromLngLats(hollowPolygon.coordinates().get(0));
                        List<SlicePoint> hollowSlicePoints = getSlicePoint(hollowPolygonOutLine, sliceLine);
                        slicePoints.addAll(hollowSlicePoints);
                    }
                }

                return new SlicePolygonByLineResult(slicePoints, polygons);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //确认切割线是否能自相交成多边形并且在图形内部，如果是则进行内部切割
    List<Polygon> doSaveQiegeCheckInside(Polygon polygon, LineString sliceLine) {
        List<Point> sliceLinePoints = sliceLine.coordinates();
        if (sliceLinePoints.size() < 3) {
            return null;
        }
        try {
            GeometryFactory geometryFactory = new GeometryFactory();
            GeoJsonWriter jsonWriter = new GeoJsonWriter(17);
            GeoJsonReader jsonReader = new GeoJsonReader(geometryFactory);

            List<LineString> lineStrings = new ArrayList<>();
            List<org.locationtech.jts.geom.LineString> lineGeometryList = new ArrayList<>();
            //分解后续线段
            for (int i = 0; i < sliceLinePoints.size() - 1; i++) {
                List<Point> data = new ArrayList<>();
                data.add(sliceLinePoints.get(i));
                data.add(sliceLinePoints.get(i +1));
                LineString lineString = LineString.fromLngLats(data);
                lineStrings.add(LineString.fromLngLats(data));
                lineGeometryList.add((org.locationtech.jts.geom.LineString) jsonReader.read(toJson(lineString)));
            }

            org.locationtech.jts.geom.Polygon sourcePolygonGeometry = (org.locationtech.jts.geom.Polygon) jsonReader.read(toJson(polygon));

            //遍历线段，找到第一个相交点
            org.locationtech.jts.geom.Point intersectionPoint = null;
            int startLineIndex = 0;
            int endLineIndex = 0;
            for (int i = 0; i < lineGeometryList.size() - 2; i++) {
                org.locationtech.jts.geom.LineString lineString1 = lineGeometryList.get(i);
                for (int j = i + 2; j < lineGeometryList.size(); j++) {
                    org.locationtech.jts.geom.LineString lineString2 = lineGeometryList.get(j);

                    org.locationtech.jts.geom.Geometry result = lineString1.intersection(lineString2);
                    if (result instanceof org.locationtech.jts.geom.Point) {
                        org.locationtech.jts.geom.Point point = (org.locationtech.jts.geom.Point) result;

                        boolean isContains = sourcePolygonGeometry.contains(point);
                        if (isContains) {
                            //组建新的线段
                            intersectionPoint = point;
                            startLineIndex = i;
                            endLineIndex = j;
                            break;
                        }
                    }
                }
            }
            if (intersectionPoint != null) {
                List<Point> newPoints = new ArrayList<>();
                newPoints.add(Point.fromLngLat(intersectionPoint.getX(), intersectionPoint.getY()));
                for (int i = startLineIndex; i < endLineIndex && i < sliceLinePoints.size(); i++) {
                    newPoints.add(sliceLinePoints.get(i + 1));
                }
                //闭合
                newPoints.add(Point.fromLngLat(intersectionPoint.getX(), intersectionPoint.getY()));

                List<List<Point>> data = new ArrayList<>();
                data.add(newPoints);
                Polygon slicePolygon = Polygon.fromLngLats(data);

                org.locationtech.jts.geom.Geometry slicePolygonGeometry = jsonReader.read(toJson(slicePolygon));

                List<Polygon> polygons = new ArrayList<>();
                //取交集
                org.locationtech.jts.geom.Geometry intersectionGeometry = sourcePolygonGeometry.intersection(slicePolygonGeometry);
                if (intersectionGeometry instanceof org.locationtech.jts.geom.MultiPolygon) {
                    org.locationtech.jts.geom.MultiPolygon multiPolygon = (org.locationtech.jts.geom.MultiPolygon) intersectionGeometry;
                    for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
                        org.locationtech.jts.geom.Geometry polygonGeometry = multiPolygon.getGeometryN(i);
                        if (polygonGeometry instanceof org.locationtech.jts.geom.Polygon) {
                            polygons.add(Polygon.fromJson(jsonWriter.write(polygonGeometry)));
                        }
                    }
                } else if (intersectionGeometry instanceof org.locationtech.jts.geom.Polygon) {
                    polygons.add(Polygon.fromJson(jsonWriter.write(intersectionGeometry)));
                }

                //进行去重切割操作
                org.locationtech.jts.geom.Geometry sliceResult = sourcePolygonGeometry.difference(slicePolygonGeometry);

                if (sliceResult instanceof org.locationtech.jts.geom.MultiPolygon) {
                    org.locationtech.jts.geom.MultiPolygon multiPolygon = (org.locationtech.jts.geom.MultiPolygon) sliceResult;
                    for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
                        org.locationtech.jts.geom.Geometry polygonGeometry = multiPolygon.getGeometryN(i);
                        if (polygonGeometry instanceof org.locationtech.jts.geom.Polygon) {
                            polygons.add(Polygon.fromJson(jsonWriter.write(polygonGeometry)));
                        }
                    }
                    return polygons;
                } else if (sliceResult instanceof org.locationtech.jts.geom.Polygon) {
                    polygons.add(Polygon.fromJson(jsonWriter.write(sliceResult)));
                    return polygons;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    private List<SlicePoint> getSlicePoint(
            LineString polygonOutLine, LineString sliceLine) throws Exception {
        List<SlicePoint> slicePoints = new ArrayList<>();

        GeometryFactory geometryFactory = new GeometryFactory();
        GeoJsonWriter jsonWriter = new GeoJsonWriter(17);
        GeoJsonReader jsonReader = new GeoJsonReader(geometryFactory);

        org.locationtech.jts.geom.Geometry polygonsOutLineGeometry = jsonReader.read(toJson(polygonOutLine));
        org.locationtech.jts.geom.Geometry sliceLineGeometry = jsonReader.read(toJson(sliceLine));

        //多边形被分割后的线段
        org.locationtech.jts.geom.Geometry sliceGeometry = new OverlayOp(
                polygonsOutLineGeometry, sliceLineGeometry).getResultGeometry(OverlayOp.DIFFERENCE);
        if (sliceGeometry instanceof org.locationtech.jts.geom.MultiLineString) {
            MultiLineString multiLineString = MultiLineString.fromJson(jsonWriter.write(sliceGeometry));
            if (multiLineString.lineStrings().size() < 3) {
                //只处理切割成三段的结果
                return slicePoints;
            }

            //被切割后的三条线段
            LineString slicePolygonLineFirst = multiLineString.lineStrings().get(0);
            LineString slicePolygonLineMid = multiLineString.lineStrings().get(1);
            LineString slicePolygonLineEnd = multiLineString.lineStrings().get(2);

            SlicePoint slicePoint1 = new SlicePoint(slicePolygonLineMid.coordinates().get(0),
                    slicePolygonLineFirst.coordinates().get(slicePolygonLineFirst.coordinates().size() - 2),
                    slicePolygonLineMid.coordinates().get(1),
                    sliceLine);
            slicePoints.add(slicePoint1);

            SlicePoint slicePoint2 = new SlicePoint(slicePolygonLineEnd.coordinates().get(0),
                    slicePolygonLineMid.coordinates().get(slicePolygonLineMid.coordinates().size() - 2),
                    slicePolygonLineEnd.coordinates().get(1),
                    sliceLine);

            slicePoints.add(slicePoint2);

        }
        return slicePoints;
    }


    public List<LineString> sliceLineStringByLine(List<Geometry> geometries, LineString sliceLine) {
        List<LineString> resultLineString = new ArrayList<>();
        for (Geometry geometry : geometries) {
            if (geometry instanceof MultiLineString) {
                MultiLineString multiLineString = (MultiLineString) geometry;


                //将多多边形分割为多边形列表
                List<LineString> lineStrings = new ArrayList<>();
                for (List<Point> coordinates : multiLineString.coordinates()) {
                    LineString lineString = LineString.fromLngLats(coordinates);

                    List<LineString> result = sliceLineStringByLine(lineString, sliceLine);
                    if (result != null) {
                        lineStrings.addAll(result);
                    } else {
                        lineStrings.add(lineString);
                    }
                }

                if (lineStrings.size() != multiLineString.coordinates().size()) {
                    //和原来的多边形数量不一样，则说明切割成功
                    resultLineString.addAll(lineStrings);
                }
            } else if (geometry instanceof LineString) {
                LineString lineString = (LineString) geometry;
                List<LineString> result = sliceLineStringByLine(lineString, sliceLine);
                if (result != null) {
                    resultLineString.addAll(result);
                } else {
                    resultLineString.add(lineString);
                }
            }
        }
        if (resultLineString.size() > geometries.size()) {
            //比原来的多边形数量多，则说明切割成功
            return resultLineString;
        }
        return null;
    }

    public List<LineString> sliceLineStringByLine(LineString lineString, LineString sliceLine) {
        try {
            GeometryFactory geometryFactory = new GeometryFactory();
            GeoJsonWriter jsonWriter = new GeoJsonWriter(17);
            GeoJsonReader jsonReader = new GeoJsonReader(geometryFactory);
            org.locationtech.jts.geom.Geometry sliceLineGeometry = jsonReader.read(toJson(sliceLine));


            org.locationtech.jts.geom.Geometry lineGeometry = jsonReader.read(toJson(lineString));

            //多边形被分割后的线段
            org.locationtech.jts.geom.Geometry sliceMultiLineGeometry = new OverlayOp(
                    lineGeometry, sliceLineGeometry).getResultGeometry(OverlayOp.DIFFERENCE);

            if (sliceMultiLineGeometry instanceof org.locationtech.jts.geom.MultiLineString) {
                MultiLineString sliceMultiLineString = MultiLineString.fromJson(jsonWriter.write(sliceMultiLineGeometry));
                return sliceMultiLineString.lineStrings();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    //挖孔
    public Geometry hollowPolygon(Polygon polygon, List<Point> holes) {

        List<Point> data = new ArrayList<>();
        for (Point point : holes) {
            data.add(point);
        }

        int lastIndex = data.size() - 1;
        //闭合
        if (holes.get(0).longitude() != holes.get(lastIndex).longitude()
                && holes.get(0).latitude() != holes.get(lastIndex).latitude()) {
            data.add(data.get(0));
        }
        List<List<Point>> points = new ArrayList<>();
        points.add(data);
        Polygon holesPolygon = Polygon.fromLngLats(points);

        return difference(polygon, holesPolygon);
    }

    //点是否在线上-如果intersection返回的是点，且是传入的点说明点在线上
    public boolean isPointInLine(Point point, LineString lineString) {
        Geometry geometry = intersection(point, lineString);
        if (geometry instanceof Point) {
            return true;
        }
        return false;
    }

    public Geometry difference(Geometry geometry1, Geometry geometry2) {
        try {
            GeometryFactory geometryFactory = new GeometryFactory();
            GeoJsonWriter jsonWriter = new GeoJsonWriter(17);
            GeoJsonReader jsonReader = new GeoJsonReader(geometryFactory);

            org.locationtech.jts.geom.Geometry polygonGeometry1 = jsonReader.read(toJson(geometry1));
            org.locationtech.jts.geom.Geometry polygonGeometry2 = jsonReader.read(toJson(geometry2));

            org.locationtech.jts.geom.Geometry resultGeometry = polygonGeometry1.difference(polygonGeometry2);

            if (resultGeometry.isEmpty()) {
                return null;
            }
            if (resultGeometry instanceof org.locationtech.jts.geom.MultiPolygon) {
                return MultiPolygon.fromJson(jsonWriter.write(resultGeometry));
            } else if (resultGeometry instanceof org.locationtech.jts.geom.Polygon) {
                return Polygon.fromJson(jsonWriter.write(resultGeometry));
            }
        } catch (Exception e){
            e.printStackTrace();
        }

        return null;
    }

    public Geometry intersection(Geometry geometry1, Geometry geometry2) {
        try {
            GeometryFactory geometryFactory = new GeometryFactory();
            GeoJsonWriter jsonWriter = new GeoJsonWriter(17);
            GeoJsonReader jsonReader = new GeoJsonReader(geometryFactory);

            org.locationtech.jts.geom.Geometry polygonGeometry1 = jsonReader.read(toJson(geometry1));
            org.locationtech.jts.geom.Geometry polygonGeometry2 = jsonReader.read(toJson(geometry2));

            org.locationtech.jts.geom.Geometry resultGeometry = polygonGeometry1.intersection(polygonGeometry2);

            if (resultGeometry.isEmpty()) {
                return null;
            }
            if (resultGeometry instanceof org.locationtech.jts.geom.MultiPolygon) {
                return MultiPolygon.fromJson(jsonWriter.write(resultGeometry));
            } else if (resultGeometry instanceof org.locationtech.jts.geom.Polygon) {
                return Polygon.fromJson(jsonWriter.write(resultGeometry));
            } else if (resultGeometry instanceof org.locationtech.jts.geom.LineString) {
                return LineString.fromJson(jsonWriter.write(resultGeometry));
            } else if (resultGeometry instanceof org.locationtech.jts.geom.MultiLineString) {
                return MultiLineString.fromJson(jsonWriter.write(resultGeometry));
            } else if (resultGeometry instanceof org.locationtech.jts.geom.Point) {
                return Point.fromJson(jsonWriter.write(resultGeometry));
            } else if (resultGeometry instanceof org.locationtech.jts.geom.MultiPoint) {
                return MultiPoint.fromJson(jsonWriter.write(resultGeometry));
            }
        } catch (Exception e){
            e.printStackTrace();
        }

        return null;
    }


    private String toJson(Geometry geometry) {
        return MapboxJsonHelper.geometryToJson(geometry);
    }

    public static class SlicePolygonByLineResult {

        List<SlicePoint> slicePoints;

        List<Polygon> resultPolygons;

        private SlicePolygonByLineResult() {
            slicePoints = new ArrayList<>();
            resultPolygons = new ArrayList<>();
        }

        private SlicePolygonByLineResult(
                List<Polygon> resultPolygons) {
            this.resultPolygons = resultPolygons;
        }

        private SlicePolygonByLineResult(
                List<SlicePoint> slicePoints, List<Polygon> resultPolygons) {
            this.slicePoints = slicePoints;
            this.resultPolygons = resultPolygons;
        }

        public List<SlicePoint> getSlicePoints() {
            return slicePoints;
        }

        public List<Polygon> getResultPolygons() {
            return resultPolygons;
        }

        void addResult(SlicePolygonByLineResult result) {
            if (result.slicePoints != null && result.slicePoints.size() > 0) {
                slicePoints.addAll(result.slicePoints);
            }
            if (result.resultPolygons != null && result.resultPolygons.size() > 0) {
                resultPolygons.addAll(result.resultPolygons);
            }
        }

    }

    public static class SlicePoint {

        String id;

        //切割点
        Point slicePoint;

        //被切割点切割的部分线段
        LineString intersectionLine;

        LineString sliceLine;

        public SlicePoint(Point slicePoint, Point lineStart, Point lineEnd, LineString sliceLine) {
            this.id = StringUtils.generateId();
            this.slicePoint = slicePoint;
            List<Point> points = new ArrayList<>();
            points.add(lineStart);
            points.add(lineEnd);
            intersectionLine = LineString.fromLngLats(points);
            this.sliceLine = sliceLine;
        }

        public String getId() {
            return id;
        }

        public Point getSlicePoint() {
            return slicePoint;
        }

        public LineString getIntersectionLine() {
            return intersectionLine;
        }

        public LineString getSliceLine() {
            return sliceLine;
        }
    }

}
